#ifndef __HUA_INST_H__
#define __HUA_INST_H__

namespace hua
{
	enum // inst.operation.family
	{
		ALU = 1,
		FPU0,
		FPU1,
		BU,
		ADV,
	};

	enum // inst.operation.cmd
	{
        // moving instruction
		MOV = 1,

		// arithmetic instructions
		ADD,
		SUB,
		MUL,
		DIV,
		MOD,

		// logical instructions
		ANDAND,
		OROR,
		LT,
		LE,
		EQ,
		NE,

		// bitwise instructions
        NOT,
		AND,
		OR,
		XOR,
		SL,
		SR,

		// branching instructions
		J,
		JT,
		JF,
		CALL,
		RET,

		// advanced instructions
		NEW,
		DE,
		ARR,
		DEARR,
		AT,
	};
	
	enum // inst.operand.attribute.addition
	{
		SYSTEM = 1, //
		CONST, // constant 
		REAL, // dereference a virtual stack pointer variable
		VIRTUAL, // a virtual stack variable
		LA_VIRTUAL, // loading a virtual stack variable's address
	};
	
	class Operand
	{
    public:
        Operand(unsigned char ucDataType = 0, unsigned char ucAddition = 0, int iVariable = 0);
        Operand operator&();
    
    public:
		unsigned char m_ucDataType: 5;
        unsigned char m_ucAddition: 3;
        int m_iVariable;
	};

	class Inst
	{
    public:
        Inst(unsigned char cmd = 0);
		Inst(unsigned char cmd, Operand a);
		Inst(unsigned char cmd, Operand a, Operand b);
		Inst(unsigned char cmd, Operand a, Operand b, Operand c);

		Inst& operator() (unsigned char cmd);
		Inst& operator() (unsigned char cmd, Operand a);
		Inst& operator() (unsigned char cmd, Operand a, Operand b);
		Inst& operator() (unsigned char cmd, Operand a, Operand b, Operand c);
        
        inline void setOperand(int i, unsigned char ucAttribute, int iVariable)
        {
            m_oOperandAttribute[i].m_ucDataType = ucAttribute>>3;
            m_oOperandAttribute[i].m_ucAddition = ucAttribute & 0x03;
            m_iOperandVariable[i] = iVariable;
        }
        
        inline void setOperand(int i, unsigned char ucDataType, unsigned char ucAddition, int iVariable)
        {
            m_oOperandAttribute[i].m_ucDataType = ucDataType;
            m_oOperandAttribute[i].m_ucAddition = ucAddition;
            m_iOperandVariable[i] = iVariable;
        }
        
    public:
		// inst.operation
		unsigned char m_ucFamily: 3;
		unsigned char m_ucCmd: 5;
		
		// inst.operand.attribute
        struct
        {
            unsigned char m_ucDataType: 5;
            unsigned char m_ucAddition: 3;
        } m_oOperandAttribute[3];
		
		// inst.operand.variable
		int m_iOperandVariable[3];
	};
}

#endif
